/* 
 * File:   Expression.cpp
 * Author: Gab'z
 * 
 * Created on 29 mai 2012, 12:25
 */

#include "Expression.h"
#include "model/memento/ContextMemento.h"
#include "model/Context.h"

namespace calculator {

    Expression::Expression() : Constant() {
        // constructeur privé utilisé pour le clonage ou l'ajout de commandes
    }

    Expression::Expression(const Command* command) : Constant() {
        // on crée une expression avec au minimum une constante, on la stocke 
        // sous la forme d'un ensemble de constante qu'on evaluera l'une 
        // après l'autre à l'appel de eval
        _expression.push_back(command->clone());
    }

    Expression::Expression(const Expression* exp1, const Expression* exp2, const Command* command) : Constant() {
        for (std::list<const Command*>::const_iterator it = exp1->_expression.begin();
                it != exp1->_expression.end();
                it++) {
            _expression.push_back((*it)->clone());
        }
        for (std::list<const Command*>::const_iterator it = exp2->_expression.begin();
                it != exp2->_expression.end();
                it++) {
            _expression.push_back((*it)->clone());
        }
        _expression.push_back(command->clone());
    }

    Expression::Expression(const Command* command1, const Command* command2, const Command* command3) : Constant() {
        const Expression* exp1 = dynamic_cast<const Expression*> (command1);
        const Expression* exp2 = dynamic_cast<const Expression*> (command2);

        if (exp1 != 0) {
            for (std::list<const Command*>::const_iterator it = exp1->_expression.begin();
                    it != exp1->_expression.end();
                    it++) {
                _expression.push_back((*it)->clone());
            }
            _expression.push_back(command2->clone());
        } else if (exp2 != 0) {
            _expression.push_back(command1->clone());
            for (std::list<const Command*>::const_iterator it = exp2->_expression.begin();
                    it != exp1->_expression.end();
                    it++) {
                _expression.push_back((*it)->clone());
            }
        } else {
            _expression.push_back(command1->clone());
            _expression.push_back(command2->clone());
        }
        _expression.push_back(command3->clone());
    }

    Expression::Expression(const Command* command1, const Command* command2) : Constant() {
        const Expression* exp1 = dynamic_cast<const Expression*> (command1);
        if (exp1 != 0) {
            for (std::list<const Command*>::const_iterator it = exp1->_expression.begin();
                    it != exp1->_expression.end();
                    it++) {
                _expression.push_back((*it)->clone());
            }
        } else {
            _expression.push_back(command1->clone());
        }
        _expression.push_back(command2->clone());
    }

    Expression::~Expression() {
        for (std::list<const Command*>::const_iterator it = _expression.begin();
                it != _expression.end();
                it++) {
            delete *it;
        }
        _expression.clear();
    }

    Expression* Expression::clone() const {
        Expression* exp = new Expression();
        for (std::list<const Command*>::const_iterator it = _expression.begin();
                it != _expression.end();
                it++) {
            exp->_expression.push_back((*it)->clone());
        }
        return exp;
    }

    std::string Expression::toString() const {
        std::string str = "'";
        std::list<const Command*>::const_iterator it = _expression.begin();
        str += (*it)->toString();
        while (++it != _expression.end()) {
            str += " " + (*it)->toString();
        }
        str.append("'");
        return str;
    }

    void Expression::append(const Command* command) {
        _expression.push_back(command->clone());
    }

    const Command* Expression::getFirstCommand() const {
        return *(_expression.begin());
    }

    void Expression::removeFirstCommand() {
        delete *(_expression.begin());
        _expression.pop_front();
    }

    bool Expression::empty() const {
        return _expression.empty();
    }
}
